/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.jackrabbit.core.TransientRepository;
import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader;
import org.apache.jackrabbit.core.nodetype.compact.ParseException;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.editor.EditorPage;
import org.gidoo.cms.login.CommonLoginPage;
import org.gidoo.cms.login.GidooCMSSession;
import org.gidoo.cms.publisher.PublisherPage;
import org.gidoo.cms.view.ContentView;
import org.gidoo.cms.view.UrlCodingStrategy;
import org.apache.wicket.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.extensions.ajax.markup.html.form.upload.UploadWebRequest;
import org.apache.wicket.markup.html.WebPage;
import org.gidoo.cms.editor.edit.EditorComponent;
import org.gidoo.cms.editor.edit.SimpleEditorComponent;
import org.gidoo.cms.jcr.JcrHelper;
import org.gidoo.cms.view.XSLTTransformFailedException;
/**
 * This is the main application class. 
 * Initialization and mounting of path names is done here.
 *
 * @author <a href="mailto:tho.krause@gmail.com">Thomas Krause</a>
 */

public class GidooCMS extends AuthenticatedWebApplication
{
  
  public static String ACTION_LOGGER = "gidooCMS Action Logger";
  
  private String realPathToContext;
  private Repository repository;
  
  /** The XSLT transformer factory. */
  private TransformerFactory tFactory;
  
  /** The XSLT transformer. */
  private Transformer transformer;
  
  /**
   * Constructor. 
   */
  public GidooCMS()
  {
  }
  
  
  public Class getHomePage()
  {
    return RedirectPage.class;
  }

  /**
   * Override this function to change between developement and deployment mode.
   * @return Either {@link #DEVELOPMENT} or  {@link #DEPLOYMENT}.
   */
  @Override
  public String getConfigurationType()
  {
    return DEVELOPMENT;
    //return DEPLOYMENT;
  }
  
  
  
  /**
   * Initializes the application.
   * Mind to call <code>super.init()</code> when overriding this.
   */
  @Override
  protected void init()
  {
    super.init();
    
    realPathToContext = getServletContext().getRealPath("/");
    if (!realPathToContext.endsWith("/"))
    {
      realPathToContext = realPathToContext + "/";
    }
    
    System.setProperty("java.security.auth.login.config", 
      realPathToContext + "META-INF/jaas.config"); 
    
    try
    {

      String configFile = realPathToContext + "META-INF/repository.xml";
      String repHomeDir = realPathToContext + "WEB-INF/repository";
      
      repository = new TransientRepository(configFile, repHomeDir);

      
      // read in node type definition
      ResourceReference r = new ResourceReference(JcrHelper.class, "nodetypes.cnd");
      r.bind(this);
      InputStreamReader reader;
            
      reader = new InputStreamReader(r.getResource().getResourceStream().getInputStream());
      CompactNodeTypeDefReader cndReader = new CompactNodeTypeDefReader(reader, 
          "nodetypes.cnd");
      
      List ntdList = cndReader.getNodeTypeDefs();
      Session s = repository.login(new SimpleCredentials(("admin"), new char[0]));
      
      // Namespaces
      try
      {
        s.getWorkspace().getNamespaceRegistry().registerNamespace("cms", "http://gidoo.org/cms");
      }
      catch(NamespaceException ex)
      {
        // ignore
      }
      
      NodeTypeManagerImpl manager = (NodeTypeManagerImpl) s.getWorkspace().getNodeTypeManager();
      NodeTypeRegistry ntreg = manager.getNodeTypeRegistry();
      
      Iterator it = ntdList.iterator();
      while(it.hasNext())
      {
        NodeTypeDef def = (NodeTypeDef) it.next();
        try
        {
          ntreg.registerNodeType(def);
        }
        catch (InvalidNodeTypeDefException ex)
        {
          // ignore
        }
      }
      
      s.save();
      
      // add default nodes
      Node root = s.getRootNode();
       Logger.getAnonymousLogger().log(Level.INFO, "checking for node");
      if(!root.hasNode("users"))
      {
        root.addNode("users");
        Logger.getAnonymousLogger().log(Level.INFO, "users node added");
      }
      if(!root.hasNode("sections"))
      {
        root.addNode("sections");
        Logger.getAnonymousLogger().log(Level.INFO, "sections node added");
      }
      if(!root.hasNode("drafts"))
      {
        root.addNode("drafts");
        Logger.getAnonymousLogger().log(Level.INFO, "drafts node added");
      }
      
      root.save();
      
      s.logout();
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(GidooCMS.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(ResourceStreamNotFoundException ex)
    {
      Logger.getLogger(GidooCMS.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(ParseException ex)
    {
      Logger.getLogger(GidooCMS.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch (IOException ex)
    {
      Logger.getLogger(GidooCMS.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    initMountUrls();
  }
  
  
  /**
   * The paths for the different parts of the application 
   * (CMS, editor UI, publishing UI, adminstration UI) are mounted here using
   * the configuration variables which were set by the constructor.<br><br>
   * 
   * Please always call <code>super()</code> first if you want to add some additional paths.
   */
  protected void initMountUrls()
  {
    mount(new UrlCodingStrategy(getCMSMainPage(), getCMSPath()));
    mountBookmarkablePage(getCMSEditPath(), EditorPage.class);
    mountBookmarkablePage(getCMSPublishPath(), PublisherPage.class);
    mountBookmarkablePage(getCMSAdminPath(), AdminPage.class);
  }
  

  protected Class<? extends AuthenticatedWebSession> getWebSessionClass()
  {
    return GidooCMSSession.class;
  }

  protected Class<? extends WebPage> getSignInPageClass()
  {
    return CommonLoginPage.class;
  }

  @Override
  protected WebRequest newWebRequest(HttpServletRequest servletRequest)
  {
    return new UploadWebRequest(servletRequest);
  }
  
  
  /**
   * The path where to mount the CMS part of the application.
   * @see #initMountUrls()
   */
  public String getCMSPath()
  {
    return "cms";
  }
  
  /**
   * The path where to mount the editor UI part of the application.
   * @see #initMountUrls()
   */
  public String getCMSEditPath()
  {
    return "edit";
  }
  
  /**
   * The path where to mount the publishing UI part of the application.
   * @see #initMountUrls()
   */
  public String getCMSPublishPath()
  {
    return "publish";
  }
  
  /**
   * The path where to mount the administration UI part of the application.
   * @see #initMountUrls()
   */
  public String getCMSAdminPath()
  {
    return "admin";
  }
  
  /**
   * The page which is used as the view of the CMS.
   * @see #init()
   */
  public Class<? extends WebPage> getCMSMainPage()
  {
    return ContentView.class;
  }
  
  /**
   * The editor component that is used at the editor-UI.
   */
  public Class<? extends EditorComponent> getEditorComponent()
  {
    return SimpleEditorComponent.class;
  }
  
  /** 
   * Returns the path of this context on the file system of the server.
   * Always ends with an "/".
   */
  public String getRealPathToContext()
  {
    return realPathToContext;
  }


  /** Return the JCR repository of the web application. */
  public Repository getRepository()
  {
    return repository;
  }

  
  
  /** Parses the XML and produces the content. */
  public String transformContent(String input)
    throws XSLTTransformFailedException
  {
    try
    {
      if(transformer == null || tFactory == null)
      {    
        tFactory = TransformerFactory.newInstance();
    
        Logger.getLogger(GidooCMS.class.getName()).log(
          Level.INFO, "reading in the XSLT-Script");
        
        File xsltScript = new File(getRealPathToContext() + "/WEB-INF/xml/content.xsl");
        if(!xsltScript.exists())
        {
          throw(new XSLTTransformFailedException("The XSLT-script could not be found."));
        }
        
        transformer = tFactory.newTransformer(new StreamSource(xsltScript));
      }
      
      StringWriter w = new StringWriter();

      transformer.transform(new StreamSource(new StringReader(input)), new StreamResult(w));

      return  w.toString();
    }
    catch (Exception ex)
    {
      throw(new XSLTTransformFailedException(ex.getMessage()));
    }
  }
  
  
}
